#include "SmoothWindowSizeAnimation.h"

///Copyright (c) 2009-2010 T. Klepzig 

map<int, SmoothWindowSizeAnimation*> SmoothWindowSizeAnimation::instances;
int SmoothWindowSizeAnimation::instanceCounter = 0;

SmoothWindowSizeAnimation::SmoothWindowSizeAnimation(HWND hWnd)
{	
	this->hWnd = hWnd;
	instanceId = instanceCounter++;
	instances[instanceId] = this;

	onAnimationStartedPtr=0;
	onAnimationCancelledPtr=0;
	onAnimationFinishedPtr=0;

	widthAnimation = new SmoothWindowSideAnimation(hWnd, (LPVOID)instanceId);
	heightAnimation = new SmoothWindowSideAnimation(hWnd, (LPVOID)instanceId);

	widthAnimation->AnimationStarted(widthAnimation_AnimationStarted);
	widthAnimation->AnimationFinished(widthAnimation_AnimationFinished);
	widthAnimation->ValueChanged(widthAnimation_ValueChanged);
	
	heightAnimation->AnimationStarted(heightAnimation_AnimationStarted);
	heightAnimation->AnimationFinished(heightAnimation_AnimationFinished);
	heightAnimation->ValueChanged(heightAnimation_ValueChanged);

}

SmoothWindowSizeAnimation::~SmoothWindowSizeAnimation()
{
	delete widthAnimation;
	widthAnimation = 0;

	delete heightAnimation;
	heightAnimation = 0;

	instances.erase(instanceId);
}

HWND SmoothWindowSizeAnimation::GetHWnd()
{
	return hWnd;
}

bool SmoothWindowSizeAnimation::IsRunning()
{
	return widthAnimation->IsRunning() || heightAnimation->IsRunning();
}


bool SmoothWindowSizeAnimation::StartAnimation(int cxSpeed, int cySpeed, SIZE startSize, SIZE endSize, bool widthFirst)
{
	if (widthAnimation->IsRunning() || heightAnimation->IsRunning())
		return false;

	this->widthFirst = widthFirst;
	this->cxSpeed = cxSpeed;
	this->cySpeed = cySpeed;
	this->startSize = startSize;
	this->endSize = endSize;

	if (widthFirst)
		StartWidthAnimation();	
	else
		StartHeightAnimation();	

	return true;
}

void SmoothWindowSizeAnimation::CancelAnimation()
{
	widthAnimation->CancelAnimation();
	heightAnimation->CancelAnimation();
}

void SmoothWindowSizeAnimation::AnimationStarted(WNDSIZEANIMATIONPROC ptr)
{
	this->onAnimationStartedPtr=ptr;
}

void SmoothWindowSizeAnimation::AnimationCancelled(WNDSIZEANIMATIONPROC ptr)
{
	this->onAnimationCancelledPtr=ptr;
}

void SmoothWindowSizeAnimation::AnimationFinished(WNDSIZEANIMATIONPROC ptr)
{
	this->onAnimationFinishedPtr=ptr;
}


void SmoothWindowSizeAnimation::CallWndSizeAnimationEvent(WNDSIZEANIMATIONPROC ptr)
{
	if (ptr)
		ptr(this);
}


void SmoothWindowSizeAnimation::StartWidthAnimation()
{
	RECT r;
	GetWindowRect(hWnd, &r);

	int amount = endSize.cx - startSize.cx;

	widthAnimation->StartAnimation(cxSpeed, RECTWIDTH(r), amount, WindowEdge::WE_WIDTH);
}

void SmoothWindowSizeAnimation::StartHeightAnimation()
{
	RECT r;
	GetWindowRect(hWnd, &r);

	int amount = endSize.cy - startSize.cy;

	heightAnimation->StartAnimation(cySpeed, RECTHEIGHT(r), amount, WindowEdge::WE_HEIGHT);
}



void SmoothWindowSizeAnimation::widthAnimation_ValueChanged(SmoothWindowSideAnimation* sender, int step, int currentValue, LPVOID tag)
{
	RECT r;
	GetWindowRect(instances[(int)tag]->hWnd, &r);
	SetWindowPos(instances[(int)tag]->hWnd, 0, r.left - step / 2, r.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}

void SmoothWindowSizeAnimation::heightAnimation_ValueChanged(SmoothWindowSideAnimation* sender, int step, int currentValue, LPVOID tag)
{
	RECT r;
	GetWindowRect(instances[(int)tag]->hWnd, &r);
	SetWindowPos(instances[(int)tag]->hWnd, 0, r.left, r.top - step / 2, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}


void SmoothWindowSizeAnimation::widthAnimation_AnimationStarted(SmoothWindowSideAnimation* sender, LPVOID tag)
{
	if (instances[(int)tag]->widthFirst)
		instances[(int)tag]->CallWndSizeAnimationEvent(instances[(int)tag]->onAnimationStartedPtr);
}

void SmoothWindowSizeAnimation::widthAnimation_AnimationFinished(SmoothWindowSideAnimation* sender, LPVOID tag)
{
	if (!instances[(int)tag]->widthFirst)
		instances[(int)tag]->CallWndSizeAnimationEvent(instances[(int)tag]->onAnimationFinishedPtr);
	else
		instances[(int)tag]->StartHeightAnimation();
}


void SmoothWindowSizeAnimation::heightAnimation_AnimationStarted(SmoothWindowSideAnimation* sender, LPVOID tag)
{
	if (!instances[(int)tag]->widthFirst)
		instances[(int)tag]->CallWndSizeAnimationEvent(instances[(int)tag]->onAnimationStartedPtr);
}

void SmoothWindowSizeAnimation::heightAnimation_AnimationFinished(SmoothWindowSideAnimation* sender, LPVOID tag)
{
	if (!instances[(int)tag]->widthFirst)
		instances[(int)tag]->StartWidthAnimation();
	else
		instances[(int)tag]->CallWndSizeAnimationEvent(instances[(int)tag]->onAnimationFinishedPtr);
}

